/*
 * ExternalSensor.cpp
 *
 *  Created on: Feb 2, 2009
 *      Author: Andrzej Olchawa
 *      mailto: andrzejolchawa@gmail.com
 *      http://www.hardtechnology.org
 *      This is a part of the Armazd project, which is covered by
 *      GNU GPL v2 license.
 */

#include "ExternalSensor.h"

ExternalSensor::ExternalSensor()
{
	sensorMessage = NULL;
	rawMessage = "sensor message";

	loadConfiguration();

	sg_init();

	if (sg_drop_privileges() != 0) {
		perror("Error. Failed to drop privileges");
		return;
	}

	sg_snapshot();

	converter = new HTConverter();
}

ExternalSensor::~ExternalSensor()
{
	if (rawMessage)
	{
		delete [] rawMessage;
	}

	if (sensorMessage)
	{
		delete sensorMessage;
	}

	sg_shutdown();

	if (converter)
	{
		delete converter;
	}
}

char *ExternalSensor::getRawMessage()
{
	return (char*)this->getStats().c_str();
}

string ExternalSensor::getStats()
{
	string stats = "";

	for (vector<string>::iterator it = this->listOfStats.begin(); it < this->listOfStats.end(); it++)
	{
		if (strcmp(it->c_str(), STATS_CPU) == 0)
		{
			stats += this->getCpuStats();
		}
		else if (strcmp(it->c_str(), STATS_DISK) == 0)
		{
			stats += this->getDiskStats();
		}
	}

	return stats;
}

string ExternalSensor::getDiskStats()
{
	string diskStats = "### disk_stats - ";
	int num_diskio_stats;

	diskio_stats = sg_get_disk_io_stats_diff(&num_diskio_stats);
	if (diskio_stats == NULL){
		perror("Error. Failed to get disk stats");
		return diskStats + "Error. Failed to get disk stats";
	}

	if ( (diskio_stats = sg_get_disk_io_stats_diff(&num_diskio_stats)) != NULL)
	{
		long long total_write=0;
		long long total_read=0;

		for(int x = 0; x < num_diskio_stats; x++)
		{
			diskStats += "Disk Name:" + string(diskio_stats->disk_name) + ", " +
						 "Disk read:" + longLongIntToStr(diskio_stats->read_bytes / 1024) + ", " +
						 "Disk write:" + longLongIntToStr(diskio_stats->write_bytes / 1024) + ", " +
						 "Disk systime:" + longLongIntToStr((long) diskio_stats->systime) + ", ";

			total_write+=diskio_stats->write_bytes;
			total_read+=diskio_stats->read_bytes;

			diskio_stats++;

		}
		diskStats += "Total Disk IO: Disk Total read:" + longLongIntToStr(total_read / 1024) + ", " +
									"Disk Total write:" + longLongIntToStr(total_write / 1024) + "; ";
	}
	else
	{
		diskStats += "disk_stats: error";
	}

	return diskStats;

}

string ExternalSensor::getCpuStats()
{
	string cpuStats = "### cpu_stats - ";

	if ((cpu_percent = sg_get_cpu_percents()) != NULL)
	{
		sg_snapshot();
		cpuStats += "User CPU: " + this->doubleToStr(cpu_percent->user) +
					", Kernel CPU: " + this->doubleToStr(cpu_percent->kernel) +
					", IOWait CPU: " + this->doubleToStr(cpu_percent->iowait) +
					", Swap CPU: " + this->doubleToStr(cpu_percent->swap) +
					", Nice CPU: " + this->doubleToStr(cpu_percent->nice) +
					", Idle CPU: " + this->doubleToStr(cpu_percent->idle) + "; ";
	}
	else
	{
		cpuStats += "cpu_stats: error";
	}

	return cpuStats;
}

void ExternalSensor::loadConfiguration()
{
	HTProperties properties;

	try
	{
		properties.loadProperties(STATS_CONFIG_LIST);

		for (int i=0; i<properties.getNumberOfElements(); i++)
		{
			if (strcmp(properties[i].value.c_str(), "1") == 0)
			{
				this->listOfStats.push_back(properties[i].key);
			}
		}

	}
	catch (HTException &e)
	{
		e.printException();
	}
}

string ExternalSensor::doubleToStr(double x)
{
	ostringstream output;
	if ( !(output << x) )
	{
		return "unknown";
	}
    return output.str();
}

string ExternalSensor::longLongIntToStr(long long int x)
{
	ostringstream output;
	if ( !(output << x) )
	{
		return "unknown";
	}
    return output.str();
}

SensorMessage *ExternalSensor::getSensorMessage()
{
	return sensorMessage;
}

extern "C" ExternalSensor* create()
{
    return new ExternalSensor();
}

extern "C" void destroy(ExternalSensor* p)
{
    delete p;
}
